﻿using System.IO.Ports;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;
using Launch.ViewModel;
using Model;
using Serilog;
using ZCommon;
using ZCommon.UiExtension;
using ZDriver;

namespace Launch.Views.Setting;

public partial class SerialPortSettingView : UserControl
{
    // 串口驱动
    private readonly SerialPort_Driver _serialPortDriver = Singleton<SerialPort_Driver>.Instance();

    // ViewModel
    private readonly SerialPortSettingVm _vm;

    // 定时器,用于循环发送数据到节点
    private readonly System.Timers.Timer _send2NodeTimer = new();
    // private readonly DispatcherTimer _send2NodeTimer = new();

    // 定时器,用于定时显示串口接收数据
    private readonly System.Timers.Timer _showReceiveDataTimer = new(1000);

    // 所有收到的数据
    private Queue<string> _allReceivedData = new();

    // 所有节点收到的总字节数
    Dictionary<int, uint> _allNodeReceivedCount = new();

    public SerialPortSettingView()
    {
        InitializeComponent();
        _vm = new SerialPortSettingVm();
        DataContext = _vm;

        // 连接定时器事件
        _send2NodeTimer.Elapsed += (s, e) =>
        {
            if (!_serialPortDriver.IsOpen())
            {
                Log.Warning("串口未连接,无法发送数据");
                _send2NodeTimer.Stop();
                return;
            }

            BtnSend2NodeOnce_OnClick(null, null);
        };

        // 定时显示接收到的原始数据
        _showReceiveDataTimer.Elapsed += (s, e) =>
        {
            if (_allReceivedData.Count > 0)
            {
                var allShowData = string.Join("\r\n", _allReceivedData);
                _vm.SerialPortReceivedData = allShowData;
            }
            /*
            // 在UI线程中更新接收框
            Application.Current?.Dispatcher.Invoke(() =>
            {
                // TextSerialReceive.AppendText(oneShowData + Environment.NewLine);
                // TextSerialReceive.Text = allShowData;
                TextSerialReceive.AutoScroll();
            }, DispatcherPriority.Background);
            */
        };
        _showReceiveDataTimer.Start();
    }

    /// <summary>
    ///     当接收到原始串口数据时触发
    /// </summary>
    private void OnDataReceived(object sender, byte[] data)
    {
        var oneShowData = BitConverter.ToString(data).Replace("-", " ");

        _allReceivedData.Enqueue(oneShowData);
        while (_allReceivedData.Count > 20)
        {
            _allReceivedData.Dequeue();
        }
    }

    /// <summary>
    /// 接收到解析出的1帧数据
    /// </summary>
    /// <param name="nodeId">节点id</param>
    /// <param name="rawData">节点收到的数据</param>
    private void OnOneFrame(int nodeId, List<byte> rawData)
    {
        // _vm.NodeReceiveBytesStatus
        _allNodeReceivedCount[nodeId] =
            (_allNodeReceivedCount.TryGetValue(nodeId, out var val) ? val : 0) + (uint) rawData.Count;

        // 拼接显示内容
        var statusLines = _allNodeReceivedCount.Select(kv => $"Node{kv.Key}:{kv.Value}").ToList();
        _vm.NodeReceiveBytesStatus = string.Join("\r\n", statusLines);
    }

    /// <summary>
    ///     点击连接按钮
    /// </summary>
    private void BtnConnect_OnClick(object sender, RoutedEventArgs e)
    {
        try
        {
            _serialPortDriver.Open(_vm.SelectedPortName,
                int.Parse(_vm.BaudRate),
                Enum.Parse<Parity>(_vm.Parity),
                int.Parse(_vm.DataBits),
                Enum.Parse<StopBits>(_vm.StopBits));
        }
        catch (Exception exception)
        {
            Log.Error($"请确认串口存在且没有被占用: {exception.Message}");
        }

        var msg = _serialPortDriver.IsOpen() ? "已连接" : "未连接";
        _vm.ConnectState = msg;
        Log.Information($"串口{msg}");
    }

    /// <summary>
    ///     点击断开连接按钮
    /// </summary>
    private void BtnDisconnect_OnClick(object sender, RoutedEventArgs e)
    {
        _serialPortDriver.Close();

        var msg = _serialPortDriver.IsOpen() ? "已连接" : "未连接";
        _vm.ConnectState = msg;
        Log.Information($"串口{msg}");
    }

    /// <summary>
    ///     发送数据
    /// </summary>
    private void BtnSendMsg_OnClick(object sender, RoutedEventArgs e)
    {
        if (!_serialPortDriver.IsOpen())
        {
            Log.Warning("串口未连接,无法发送数据");
            return;
        }

        // 获得数据
        var rawData = TextSerialSend.Text;
        _serialPortDriver.Write(rawData.HexToBytes());
    }

    /// <summary>
    ///     清除接收到的数据
    /// </summary>
    private void BtnSerialReceiveClear_OnClick(object sender, RoutedEventArgs e)
    {
        _allReceivedData.Clear();
        _vm.SerialPortReceivedData = "";
    }

    /// <summary>
    /// 串口接收框加载完成
    /// </summary>
    private void TextSerialReceive_Loaded(object sender, RoutedEventArgs e)
    {
        // 设置接收框最大行数和自动滚动
        TextSerialReceive.SetupAutoScrollBehavior();

        // 连接串口接收数据事件
        _serialPortDriver.DataReceived += OnDataReceived;
        // 连接串口接收到一帧数据
        Singleton<ProtocolParser>.Instance().OnOneFrame += OnOneFrame;
    }

    /// <summary>
    /// 节点接收框清除按钮点击
    /// </summary>
    private void BtnNodeReceiveClear_OnClick(object sender, RoutedEventArgs e)
    {
        _vm.NodeReceiveBytesStatus = "";
    }

    /// <summary>
    /// 发送1次数据到节点
    /// </summary>
    private void BtnSend2NodeOnce_OnClick(object sender, RoutedEventArgs e)
    {
        if (!_serialPortDriver.IsOpen())
        {
            Log.Warning("串口未连接,无法发送数据");
            return;
        }

        // 获得16进制数据字符串
        var data = _vm.SendDataToNode.HexToBytes();

        ZPS_Pc itemHeader = new ZPS_Pc
        {
            // 发送数据的类型
            U8Type = (byte) PSPCType.Data_Type,
            // 有效数据长度
            U32Length = (uint) data.Length,
            // 获得待发送的节点ID
            U16Id = _vm.NodeId,
            // 数据校验和
            U32DataChecksum = ProtocolStructCommon.Checksum_Pure(data),
        };
        // 帧头校验和
        itemHeader.U16HeaderChecksum = (ushort) ProtocolStructCommon.Checksum_ZPS_PC(itemHeader);

        // 发送帧头
        _serialPortDriver.Write(ProtocolStructCommon.StructToByteArray(ref itemHeader));
        // 发送数据体
        _serialPortDriver.Write(data);
        _vm.SendBytesCount += (uint) data.Length;
        _vm.SendFramesCount += 1;
    }

    /// <summary>
    /// 循环发送数据到节点
    /// </summary>
    private void BtnSend2NodeRepeatStart_OnClick(object sender, RoutedEventArgs e)
    {
        // 查看定时器是否已经启动
        // if (_send2NodeTimer.IsEnabled)
        if (_send2NodeTimer.Enabled)
        {
            Log.Warning("定时发送已经启动,如果要更改发送间隔,请先停止定时发送");
            return;
        }

        // 查看发送间隔
        // _send2NodeTimer.Interval = TimeSpan.FromMilliseconds(_vm.SendIntervalMs);
        _send2NodeTimer.Interval = _vm.SendIntervalMs;
        // 启动定时器
        _send2NodeTimer.Start();
    }

    /// <summary>
    /// 停止循环发送数据到节点
    /// </summary>
    private void BtnSend2NodeRepeatStop_OnClick(object sender, RoutedEventArgs e)
    {
        _send2NodeTimer.Stop();
    }
}